import math
from collections import Iterable
from collections import Iterator
from functools import reduce


def add(L=[]):
    L.append("END")
    return L


print(add([1, 2, 3]))
print(add())  # ['END']
print(add())  # ['END', 'END']


def add(L=None):
    if L is None:
        L = []
    L.append("END")
    return L


print(add())  # ['END']
print(add())  # ['END']


def person(name, age, **kw):
    print("name", name, "age", age, "other", kw)


person("huhx", 34)  # name huhx age 34 other {}
person("linux", 34, lover="liuling")  # name linux age 34 other {'lover': 'liuling'}


def fact(n):
    if n == 1:
        return 1
    return n * fact(n - 1)


print(fact(5))  # 120

L = [1, 2, 3, 4, 5, 6]
print(L[0:3])

L = list(range(100))
print(L[:5], len(L))  # [0, 1, 2, 3, 4] 100

L = (1, 2, 3, 4, 5)
print(L[:3], len(L))  # (1, 2, 3) 5
print(L[:])

d = {"a": 1, "b": 2, "c": 3}
for key in d:
    print(key, d.get(key))
for value in d.values():
    print(value, end=",")  # 3,2,1,
for key, value in d.items():
    print(key, value)

print(isinstance("abc", Iterable))  # True
print(isinstance(123, Iterable))  # False
print(isinstance([1, 2, 3], Iterable))  # True

for i, value in enumerate(["huhx", "linux", "liuling"]):
    print(i, value)

for x, y in [(1, "huhx"), (2, "linu"), (3, "linux")]:
    print(x, y)

L = list(range(1, 11))
print(L)  # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

L = []
for x in range(1, 11):
    L.append(x * x)
print(L)  # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
L = [x * x for x in range(1, 11)]
print(L)  # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
L = [x * x for x in range(1, 11) if x % 2 == 0]
print(L)  # [4, 16, 36, 64, 100]
L = [m + n for m in "ABC" for n in "XYZ"]
print(L)  # ['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
L = ['Hello', 'World', 'IBM', 'Apple']
print([s.lower() for s in L if s.startswith("H")]) # ['hello']

print(isinstance("hello", str)) # True

# create generator
# one simple way
g = (x * x for x in range(1, 10))
print(next(g))
# second way: 如果一个函数定义中包含yield关键字，那么这个函数就不再是一个普通函数，而是一个generator

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
    return "done"
g = fib(7)
print(next(g)) # 1
print(next(g)) # 1
print(next(g)) # 2

def odd():
    print("step 1")
    yield 1
    print("step 2")
    yield(3)
    print("step 3")
    yield(5)
o = odd()
print(next(o))
print(next(o))
print(next(o))

# 这个算法很牛
def triangles():
    L = [1]
    while True:
        yield L
        L.append(0)
        L = [x + y for x, y in zip(L, L[::-1])]
i = triangles()
for x in range(10):
    print(next(i))

# 对于zip和L[::-1]的测试
L = [1, 2, 7, 4]
print(L[::-1]) # [4, 7, 2, 1]
G = [x + y for x, y in zip(L, L[::-1])]
print(G) # [5, 9, 9, 5]

print(isinstance("abc", Iterator)) # False
print(isinstance(iter("abc"), Iterator)) # True

# 函数当成参数
def add(x, y, f):
    return f(x) + f(y)
print(add(-3, -8, abs)) # 11

# map()的使用
def f(x):
    return x * x
L = list(map(f, [1, 2, 3, 4, 5, 6]))
print(L) # [1, 4, 9, 16, 25, 36]

# reduce()的使用
def add(x, y):
    return x + y
print(reduce(add, [1, 3, 5, 7, 9])) # 25

name = ['adam', 'LISA', 'barT']
def firstLetterUpper(str):
    return str[:1].upper() + str[1:].lower();
L = list(map(firstLetterUpper, name))
print(L)

# filter 的使用
def is_odd(n):
    return n % 2 == 0
print(list(filter(is_odd, [1, 2, 3, 4, 5, 6, 7]))) # [2, 4, 6]

def is_palindrome(n):
    n = str(n)
    return n == n[::-1]
print(list(filter(is_palindrome, [12321, 343, 4567654, 1234, 55677]))) # [12321, 343, 4567654]

# sorted 的使用
print(sorted([9, 4, 6, 3, 8, 12, 45])) # [3, 4, 6, 8, 9, 12, 45]
print(sorted([-23, -45, -12, -90, 45, 56, 89], key=abs, reverse=True)) # [-90, 89, 56, -45, 45, -23, -12]
print(sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)) # ['about', 'bob', 'Credit', 'Zoo']

L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
def by_name(t):
    return sorted(t, key=lambda x: x[1], reverse=False)
print(by_name(L))

# 闭包函数
def lazy_sum(*args):
    def sum():
        ax = 0
        for n in args:
            ax = ax + n
        return ax
    return sum
f1 = lazy_sum(1, 3, 4, 5, 6)
f2 = lazy_sum(1, 3, 4, 5, 6)
print(f1 == f2) # False
print(f1()) # 19

def count():
    fs = []
    for i in range(1, 4):
        def f():
            return i * i
        fs.append(f)
    return fs
f1, f2, f3 = count()
print(f1, f2, f3)
print(f1()) # 9
print(f2()) # 9
print(f3()) # 9

L1, L2, L3 = [1, 2, 3]
print(L1, L2, L3) # 1 2 3

# lambda函数,lambda x: x * x
print(list(map(lambda x: x * x, [1, 3, 5, 7, 9]))) # [1, 9, 25, 49, 81]
def f(x):
    return x * x
print(list(map(f, [1, 3, 5, 7, 9]))) # [1, 9, 25, 49, 81]

